package com.easycoding.framework.repository.support;

import java.io.Serializable;  
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;  
  
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;  
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;  
import org.springframework.data.repository.NoRepositoryBean;  

import com.easycoding.framework.repository.BaseJpaRepository;
import com.easycoding.framework.repository.support.query.BuildQueryHandler;
import com.easycoding.framework.repository.support.query.QueryInfo;
import com.easycoding.framework.support.PageMan;

/**
 * 定义全局扩展Repository，可以扩展全局的自定义方法  
 * @author Wangjk
 * @Version 1.0
 * @Date 2013-3-22
 * @param <T> 实体类型
 * @param <ID> 主键类型
 */
@NoRepositoryBean  
public class JpaRepositorySupport<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>  implements BaseJpaRepository<T, ID> {  
    
	private static final Log log = LogFactory.getLog(JpaRepositorySupport.class);
	
	@SuppressWarnings("unused")
	private final EntityManager entityManager;
	
	public JpaRepositorySupport(Class<T> domainClass, EntityManager em) {  
	        super(domainClass, em);  
	        entityManager = em;
	    }  
	  
	public JpaRepositorySupport(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {  
	    super(entityInformation, entityManager);  
	    this.entityManager = entityManager;
	}

	/* (non-Javadoc)
	 * @see BaseJpaRepository#findTopOne(Sort sort)
	 */
	public T findTopOne(Sort sort) {
		return this.findTopOne(null,sort);
	}
	
	/* (non-Javadoc)
	 * @see BaseJpaRepository#findTopOne(Specification<T> specification)
	 */
	public T findTopOne(Specification<T> specification) {
		return this.findTopOne(specification,null);
	}
	
	/* (non-Javadoc)
	 * @see BaseJpaRepository#findTopOne(Specification<T> specification,Sort sort)
	 */
	public T findTopOne(Specification<T> specification,Sort sort) {
		Page<T> ts = this.findAll(specification,new PageRequest(0,1,sort));
		if(ts != null && ts.getContent() != null && !ts.getContent().isEmpty()){
			return ts.getContent().get(0);
		}
		return null;
	}

	/* (non-Javadoc)
	 * @see BaseJpaRepository#findTop(int num, Sort sort)
	 */
	public List<T> findTop(int num, Sort sort) {
		return this.findTop(null, num, sort);
	}
	
	/* (non-Javadoc)
	 * @see BaseJpaRepository#findTop(Specification<T> specification,int num)
	 */
	public List<T> findTop(Specification<T> specification,int num) {
		return this.findTop(specification, num, null);
	}
	
	/* (non-Javadoc)
	 * @see BaseJpaRepository#findTop(Specification<T> specification,int num, Sort sort)
	 */
	public List<T> findTop(Specification<T> specification,int num, Sort sort) {
		Page<T> ts = this.findAll(specification,new PageRequest(0,num,sort));
		if(ts != null ){
			return ts.getContent();
		}
		return null;
	}

	/* (non-Javadoc)
	 * @see BaseJpaRepository#findPage(PageMan pageMan)
	 */
	public List<T> findPage(PageMan pageMan) {
		return this.findPage(pageMan, null);
	}

	/* (non-Javadoc)
	 * @see BaseJpaRepository#findPage(PageMan pageMan, Sort sort)
	 */
	public List<T> findPage(PageMan pageMan, Sort sort) {
		Page<T> ts = this.findAll(new PageRequest(pageMan.getPageNo()-1,pageMan.getPageSize(),sort));
		if(ts != null){
			pageMan.setCurrent(ts.getNumberOfElements());
			pageMan.setTotalPage(ts.getTotalPages());
			pageMan.setTotalCount(ts.getTotalElements());
			return new ArrayList<T>(ts.getContent());
		}
		return null;
	}

	/* (non-Javadoc)
	 * @see BaseJpaRepository#findPage(Specification<T> specification, PageMan pageMan)
	 */
	public List<T> findPage(Specification<T> specification, PageMan pageMan) {
		return this.findPage(specification, pageMan, null);
	}

	/* (non-Javadoc)
	 * @see BaseJpaRepository#findPage(Specification<T> specification, PageMan pageMan, Sort sort)
	 */
	public List<T> findPage(Specification<T> specification, PageMan pageMan,
			Sort sort) {
		Page<T> ts = this.findAll(specification,new PageRequest(pageMan.getPageNo()-1,pageMan.getPageSize(),sort));
		if(ts != null){
			pageMan.setCurrent(ts.getNumberOfElements());
			pageMan.setTotalPage(ts.getTotalPages());
			pageMan.setTotalCount(ts.getTotalElements());
			return new ArrayList<T>(ts.getContent());
		}
		return null;
	}
	
	public List<T> findByQueryInfo(QueryInfo<T> queryInfo){
		BuildQueryHandler<T> build = new BuildQueryHandler<T>();
		Specification<T> spec = build.buildSpecification(queryInfo);
		Sort sort = build.buildSort(queryInfo);
		Long startTime = System.currentTimeMillis();
		if(queryInfo.getPageSize() > 0){//分页
			if(log.isDebugEnabled())
				log.debug("分页查询:页码:"+queryInfo.getPageNo() +",每页记录数:"+queryInfo.getPageSize());
			Page<T> ts = this.findAll(spec,new PageRequest(queryInfo.getPageNo()-1,queryInfo.getPageSize(),sort));
			if(log.isDebugEnabled()){
				Long endTime = System.currentTimeMillis();
				log.debug("查询耗时:" + (endTime - startTime) + "ms");
			}
			if(ts != null){
				queryInfo.setCurrent(ts.getNumberOfElements());
				queryInfo.setTotalPage(ts.getTotalPages());
				queryInfo.setTotal(ts.getTotalElements());
				List<T> result = new ArrayList<T>(ts.getContent());
				queryInfo.setResult(result);
				return result;
			}
		}
		else{//不分页
			List<T> result = this.findAll(spec, sort);
			if(log.isDebugEnabled()){
				Long endTime = System.currentTimeMillis();
				log.debug("查询耗时:" + (endTime - startTime) + "ms");
			}
			queryInfo.setResult(result);
			return result;
		}
		
		return null;
	}
}
